/**
 *  Copyright 2011 Pavlov Dm.
 *  Licensed under the MIT License
 */

package org.motiv.config;

import org.motiv.policy.MemoryStoreEvictionPolicy;

/**
 * A value object used to represent cache configuration.
 * <cache name="testCache1"
 *   maxElementsInMemory="10000"
 *   eternal="false"
 *   timeToIdleSeconds="3600"
 *   timeToLiveSeconds="10"
 *   overflowToDisk="true"
 *   diskPersistent="true"
 *   diskExpiryThreadIntervalSeconds="120"
 *   maxElementsOnDisk="10000"
 * />
 * @author Pavlov Dm
 */
public class CacheConfiguration implements Cloneable {
	 /**
     * Default value for maxElementsOnDisk
     */
    public static final int DEFAULT_MAX_ELEMENTS_ON_DISK = 0;
	 /**
     * Set a buffer size for the spool of approx 10MB.
     */
    public static final int DEFAULT_SPOOL_BUFFER_SIZE = 10;
	 /**
     * Default value for ttl
     */
    public static final long DEFAULT_TTL = 0;
    /**
     * Default value for tti
     */
    public static final long DEFAULT_TTI = 0;
	 /**
     * The default memory store eviction policy is LRU.
     */
    public static final MemoryStoreEvictionPolicy DEFAULT_MEMORY_STORE_EVICTION_POLICY = MemoryStoreEvictionPolicy.LRU;
    /**
     * the name of the cache.
     */
    protected volatile String name;
    /**
     * the maximum objects to be held in MemoryStore.
     */
    protected volatile int maxElementsInMemory;
    /**
     * the maximum objects to be held in the DiskStore
     */
    protected volatile int maxElementsOnDisk = DEFAULT_MAX_ELEMENTS_ON_DISK;
	 /**
     * Sets whether elements are eternal. If eternal, timeouts are ignored and the element
     * is never expired.
     */
    protected volatile boolean eternal;
    /**
     * the time to idle for an element before it expires. Is only used
     * if the element is not eternal.A value of 0 means do not check for idling.
     */
    protected volatile long timeToIdleSeconds = DEFAULT_TTI;
    /**
     * Sets the time to idle for an element before it expires. Is only used
     * if the element is not eternal. This attribute is optional in the configuration.
     * A value of 0 means do not check time to live.
     */
    protected volatile long timeToLiveSeconds = DEFAULT_TTL;
    /**
     * whether elements can overflow to disk when the in-memory cache
     * has reached the set limit.
     */
    protected volatile boolean overflowToDisk = false;
    /**
     * The size of the disk spool used to buffer writes
     */
    protected volatile int diskSpoolBufferSizeMB = DEFAULT_SPOOL_BUFFER_SIZE;
	/**
     * The policy used to evict elements from the {@link org.motiv.policy.MemoryStoreEvictionPolicy}.
     * This can be one of:
     * <ol>
     * <li>LRU - least recently used
     * <li>LFU - Less frequently used
     * <li>FIFO - first in first out, the oldest element by creation time
     * </ol>
     * The default value is LRU
     */
    protected volatile MemoryStoreEvictionPolicy memoryStoreEvictionPolicy = DEFAULT_MEMORY_STORE_EVICTION_POLICY;
    /**
     * Default constructor.
     */
    public CacheConfiguration() {
        // empty constructor
    }

    /**
     * Create a new cache configuration.
     * @param name the name of the cache. Note that "default" is a reserved name for the defaultCache.
     * @param maxElementsInMemory the maximum number of elements in memory, before they are evicted (0 == no limit)
     */
    public CacheConfiguration(String name, int maxElementsInMemory) {
        this.name = name;
        this.maxElementsInMemory = maxElementsInMemory;
    }
    /**
     * Clones this object.
     * @return a copy, which independent other than configurations than cannot change.
     */
    @Override
    public CacheConfiguration clone() {
        CacheConfiguration config;
        try {
            config = (CacheConfiguration) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
        return config;
    }  
    /**
     * Sets the name of the cache.
     * @param name the cache name. This must be unique.
     */
    public final void setName(String name) {
        if (name == null) {
            throw new IllegalArgumentException("Cache name cannot be null.");
        }
        this.name = name;
    }
	/**
     * Get cache name method
     */
    public String getName() {
        return name;
    }
    /**
     * Sets the maximum objects to be held in memory (0 = no limit).
     * @param maxElementsInMemory The maximum number of elements in memory, before they are evicted (0 == no limit)
     */
    public final void setMaxElementsInMemory(int maxElementsInMemory) {
        this.maxElementsInMemory = maxElementsInMemory;
    }
	/**
     * Get max elements in memory method
     */
    public int getMaxElementsInMemory() {
        return maxElementsInMemory;
    }
    /**
     * Sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. False by default.
     * @param eternal true for eternal
     */
    public final void setEternal(boolean eternal) {
        this.eternal = eternal;
    }
	/**
     * Check is eternal method
     */
    public boolean isEternal() {
        return eternal;
    }
    /**
     * Sets the time to idle for an element before it expires. Is only used if the element is not eternal.
     * @param timeToIdleSeconds the default amount of time to live for an element from its last accessed or modified date
     */
    public final void setTimeToIdleSeconds(long timeToIdleSeconds) {
        this.timeToIdleSeconds = timeToIdleSeconds;
    }
	/**
     * Get time to idle for an element before it expires
     */
    public long getTimeToIdleSeconds() {
        return timeToIdleSeconds;
    }
    /**
     * Sets the time to life for an element before it expires. Is only used if the element is not eternal.
     * @param timeToLiveSeconds the default amount of time to live for an element from its creation date
     */
    public final void setTimeToLiveSeconds(long timeToLiveSeconds) {
        this.timeToLiveSeconds = timeToLiveSeconds;
    }
	 /**
     * Get the time to life for an element before it expires
     */
    public long getTimeToLiveSeconds() {
        return timeToLiveSeconds;
    }
    /**
     * Sets whether elements can overflow to disk when the in-memory cache has reached the set limit.
     * @param overflowToDisk whether to use the disk store
     */
    public final void setOverflowToDisk(boolean overflowToDisk) {
        this.overflowToDisk = overflowToDisk;
    }
	/**
     * Is Overflow To Disk
     */
    public boolean isOverflowToDisk() {
        return overflowToDisk;
    }
    /**
     * Sets the disk spool size, which is used to buffer writes to the DiskStore.
     * If not set it defaults to {@link #DEFAULT_SPOOL_BUFFER_SIZE}
     * @param diskSpoolBufferSizeMB a positive number
     */
    public void setDiskSpoolBufferSizeMB(int diskSpoolBufferSizeMB) {
        if (diskSpoolBufferSizeMB <= 0) {
            this.diskSpoolBufferSizeMB = DEFAULT_SPOOL_BUFFER_SIZE;
        } else {
            this.diskSpoolBufferSizeMB = diskSpoolBufferSizeMB;
        }
    }
	 /**
     * Get the disk spool size
     */
    public int getDiskSpoolBufferSizeMB() {
        return diskSpoolBufferSizeMB;
    }
    /**
     * Sets the maximum number elements on Disk. 0 means unlimited.
     * @param maxElementsOnDisk the maximum number of Elements to allow on the disk. 0 means unlimited.
     */
    public void setMaxElementsOnDisk(int maxElementsOnDisk) {
        this.maxElementsOnDisk = maxElementsOnDisk;
    }
	 /**
     * Get max elements on disk method
     */
    public int getMaxElementsOnDisk() {
        return maxElementsOnDisk;
    }
	/**
    * Sets the eviction policy. An invalid argument will set it to null.
    * @param evictionPolicy a String representation of the policy. One of "LRU", "LFU" or "FIFO".
    */
    public final void setMemoryStoreEvictionPolicy(String sEvictionPolicy) {
        MemoryStoreEvictionPolicy evictionPolicy = MemoryStoreEvictionPolicy.fromString(sEvictionPolicy);
		 if (evictionPolicy == null) {
            this.memoryStoreEvictionPolicy = DEFAULT_MEMORY_STORE_EVICTION_POLICY;
        } else {
            this.memoryStoreEvictionPolicy = evictionPolicy;
        }
    }
	 /**
     * Get the eviction policy method
     */
    public MemoryStoreEvictionPolicy getMemoryStoreEvictionPolicy() {
        return memoryStoreEvictionPolicy;
    }
}
